/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ccy.focuslayoutmanagerproject.slice;

import ccy.focuslayoutmanager.utils.LogUtil;
import ccy.focuslayoutmanagerproject.ResourceTable;
import ccy.focuslayoutmanager.FocusLayoutManager;

import com.ohos.RecyclerContainer;
import com.harmony.recyclercomponent.ContainerGroup;
import com.harmony.recyclercomponent.HarmonyConstant;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.colors.RgbColor;

import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.components.Checkbox;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.TextField;
import ohos.agp.components.RadioContainer;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Image;

import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.RawFileEntry;

import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener{

    private static final String TAG = "MainAbilitySlice";
    private static final String RESOURCE_ID = "resId";
    private static final String DETAILS = "details";
    private static final String IMAGE_FORMAT = "image/png";
    private List<Bean> datas;
    private RecyclerContainer recyclerView;
    private FocusLayoutManager focusLayoutManager;
    private Adapter adapter;
    private Button btnLayerCount;
    private Button btnLayerPadding;
    private Button btnNormalViewGap;
    private Button btnOrientation;
    private Button btnChangeEffect;
    private Text tvFocusedPos;
    private Component emptyView;
    private Checkbox cbAutoSelect;
    private Checkbox cbInfinite;
    private ShapeElement background;
    private Runnable trigger;

    public static ToastDialog mToast;

    private int horRes[] = {ResourceTable.Media_h5, ResourceTable.Media_h6, ResourceTable.Media_h7, ResourceTable.Media_h1, ResourceTable.Media_h2,
            ResourceTable.Media_h3, ResourceTable.Media_h4, ResourceTable.Media_h5, ResourceTable.Media_h6, ResourceTable.Media_h7,
            ResourceTable.Media_h5, ResourceTable.Media_h6, ResourceTable.Media_h7, ResourceTable.Media_h1, ResourceTable.Media_h2,
            ResourceTable.Media_h3, ResourceTable.Media_h4, ResourceTable.Media_h5, ResourceTable.Media_h6, ResourceTable.Media_h7};

    private int verRes[] = {ResourceTable.Media_v5, ResourceTable.Media_v6, ResourceTable.Media_v7, ResourceTable.Media_v1, ResourceTable.Media_v2,
            ResourceTable.Media_v3, ResourceTable.Media_v4, ResourceTable.Media_v5, ResourceTable.Media_v6, ResourceTable.Media_v7};

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        background = new ShapeElement();
        background.setShape(ShapeElement.RECTANGLE);
        background.setStroke(5, new RgbColor(0x808080DD));
        background.setRgbColor(new RgbColor(0x808080DD));

        emptyView = findComponentById(ResourceTable.Id_empty);
        tvFocusedPos = (Text)findComponentById(ResourceTable.Id_tv_focus_pos);
        btnLayerCount = (Button)findComponentById(ResourceTable.Id_layerCount_btn);
        btnLayerPadding = (Button)findComponentById(ResourceTable.Id_layerPadding_btn);
        btnNormalViewGap = (Button)findComponentById(ResourceTable.Id_normalViewGap_btn);
        btnOrientation = (Button)findComponentById(ResourceTable.Id_ori_btn);
        btnChangeEffect = (Button)findComponentById(ResourceTable.Id_change_btn);
        cbAutoSelect = (Checkbox)findComponentById(ResourceTable.Id_auto_select_cb);
        cbInfinite = (Checkbox)findComponentById(ResourceTable.Id_infinite_cb);
        recyclerView = (RecyclerContainer) findComponentById(ResourceTable.Id_rv);
        final EventHandler mainHandler = new EventHandler(EventRunner.getMainEventRunner());

        btnLayerCount.setClickedListener(this);
        btnLayerPadding.setClickedListener(this);
        btnNormalViewGap.setClickedListener(this);
        btnOrientation.setClickedListener(this);
        btnChangeEffect.setClickedListener(this);

        btnLayerCount.setBackground(background);
        btnLayerPadding.setBackground(background);
        btnNormalViewGap.setBackground(background);
        btnOrientation.setBackground(background);
        btnChangeEffect.setBackground(background);

        focusLayoutManager =
                new FocusLayoutManager.Builder()
                        .layerPadding(dp2px(this,14))
                        .normalViewGap(dp2px(this,14))
                        .focusOrientation(FocusLayoutManager.FOCUS_LEFT)
                        .isAutoSelect(true)
                        .maxLayerCount(3)
                        .setOnFocusChangeListener((focusdPosition, lastFocusdPosition) -> {
                            tvFocusedPos.setText("[" + focusdPosition + "],[" + lastFocusdPosition + "]");
                            if (focusdPosition == datas.size() - 1 &&
                                    (focusLayoutManager.getFocusOrientation() == FocusLayoutManager.FOCUS_LEFT)) {
                                emptyView.setVisibility(Component.VISIBLE);
                            } else {
                                emptyView.setVisibility(Component.INVISIBLE);
                            }
                        })
                        .build();

        datas = getDatas(false);
        adapter = new Adapter(this, datas);

        recyclerView.setLayoutConfig(new ComponentContainer.LayoutConfig(HarmonyConstant.getMaximumWindowMetrics(this).getWidth(),
                HarmonyConstant.getMaximumWindowMetrics(this).getHeight() / 4));

        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(focusLayoutManager);

        cbAutoSelect.setCheckedStateChangedListener((absButton, isChecked) -> focusLayoutManager.setAutoSelect(isChecked));

        cbInfinite.setCheckedStateChangedListener((absButton, isChecked) -> {
            recyclerView.setAdapter(new Adapter(this, datas));
            if (isChecked) {
                emptyView.setVisibility(Component.INVISIBLE);
                trigger = () -> focusLayoutManager.scrollToPosition(1000);
                mainHandler.postTask(trigger);
            }
        });
    }

    public List<Bean> getDatas(boolean vertical) {
        List<Bean> datas = new ArrayList<>();
        if (vertical) {
            for (int i = 0; i < verRes.length; i++) {
                Bean bean = new Bean();
                bean.useColor = false;
                bean.background = verRes[i];
                datas.add(bean);
            }
        } else {
            for (int i = 0; i < horRes.length; i++) {
                Bean bean = new Bean();
                bean.useColor = false;
                bean.background = horRes[i];
                datas.add(bean);
            }
        }
        return datas;
    }

    public  float dp2px(Context context, float dp) {
        Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(context);
        return (int) (dp * display.get().getAttributes().densityPixels);
    }

    @Override
    public void onClick(Component component) {
        switch (component.getId()) {
            case ResourceTable.Id_layerCount_btn:
                TextField et = (TextField) findComponentById(ResourceTable.Id_layerCount);
                try {
                    int count = Integer.parseInt(et.getText());
                    if (count <= 0) {
                        ToastDialog toastDialog = new ToastDialog(this);
                        toastDialog.setAlignment(LayoutAlignment.HORIZONTAL_CENTER);
                        toastDialog.setText("Invalid.");
                        toastDialog.setDuration(2000);
                        toastDialog.show();
                        return;
                    }
                    focusLayoutManager.setMaxLayerCount(count);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                break;

            case ResourceTable.Id_layerPadding_btn:
                TextField edtLayerPadding = (TextField) findComponentById(ResourceTable.Id_layerPadding);
                try {
                    int count = Integer.parseInt(edtLayerPadding.getText());

                    focusLayoutManager.setLayerPadding(dp2px(this, count));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                break;

            case ResourceTable.Id_normalViewGap_btn:
                TextField edt = (TextField) findComponentById(ResourceTable.Id_normalViewGap);
                try {
                    int count = Integer.parseInt(edt.getText());

                    focusLayoutManager.setNormalViewGap(dp2px(this, count));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                break;

            case ResourceTable.Id_ori_btn:
                RadioContainer rg = (RadioContainer) findComponentById(ResourceTable.Id_ori_rg);
                int id = rg.getMarkedButtonId();

                switch(id){
                    case 1:
                        focusLayoutManager.setFocusOrientation(FocusLayoutManager.FOCUS_RIGHT);

                        recyclerView.setLayoutConfig(new ComponentContainer.LayoutConfig(HarmonyConstant.getMaximumWindowMetrics(this).getWidth(),
                                HarmonyConstant.getMaximumWindowMetrics(this).getHeight() / 4));

                        recyclerView.setAdapter(new Adapter(this, datas = getDatas(false)));
                        break;

                    case 2:
                        focusLayoutManager.setFocusOrientation(FocusLayoutManager.FOCUS_TOP);

                        recyclerView.setLayoutConfig(new ComponentContainer.LayoutConfig(HarmonyConstant.getMaximumWindowMetrics(this).getWidth()/4,
                                HarmonyConstant.getMaximumWindowMetrics(this).getHeight() / 2));

                        recyclerView.setMarginsLeftAndRight(400, 500);

                        recyclerView.setAdapter(new Adapter(this, datas = getDatas(true)));
                        break;

                    case 3:
                        focusLayoutManager.setFocusOrientation(FocusLayoutManager.FOCUS_BOTTOM);

                        recyclerView.setLayoutConfig(new ComponentContainer.LayoutConfig(HarmonyConstant.getMaximumWindowMetrics(this).getWidth()/4,
                                HarmonyConstant.getMaximumWindowMetrics(this).getHeight() / 2));

                        recyclerView.setMarginsLeftAndRight(400, 500);

                        recyclerView.setAdapter(new Adapter(this, datas = getDatas(true)));
                        break;

                    default:
                        focusLayoutManager.setFocusOrientation(FocusLayoutManager.FOCUS_LEFT);

                        recyclerView.setLayoutConfig(new ComponentContainer.LayoutConfig(HarmonyConstant.getMaximumWindowMetrics(this).getWidth(),
                                HarmonyConstant.getMaximumWindowMetrics(this).getHeight() / 4));

                        recyclerView.setAdapter(new Adapter(this, datas = getDatas( false)));
                        break;
                }
                break;

            case ResourceTable.Id_change_btn:
                focusLayoutManager.setMaxLayerCount(3);
                focusLayoutManager.setNormalViewGap(dp2px(this,4));
                focusLayoutManager.setLayerPadding(dp2px(this,50));
                focusLayoutManager.removeTrasitionlistener(null);
                focusLayoutManager.addTrasitionListener(new FocusLayoutManager.TrasitionListener() {
                    @Override
                    public void handleLayerView(FocusLayoutManager focusLayoutManager, Component view,
                                                int viewLayer, int maxLayerCount, int position,
                                                float fraction, float offset) {
                        float realFraction = fraction;
                        float minScale = 0.7f;
                        float maxScale = 1f;
                        float scaleDelta = maxScale - minScale;
                        float currentLayerMaxScale =
                                minScale + scaleDelta * (viewLayer + 1) / (maxLayerCount * 1.0f);
                        float currentLayerMinScale =
                                minScale + scaleDelta * viewLayer / (maxLayerCount * 1.0f);
                        float realScale =
                                currentLayerMaxScale - (currentLayerMaxScale - currentLayerMinScale) * realFraction;

                        float minAlpha = 0;
                        float maxAlpha = 1;
                        float alphaDelta = maxAlpha - minAlpha; // Total transparency difference
                        float currentLayerMaxAlpha =
                                minAlpha + alphaDelta * (viewLayer + 1) / (maxLayerCount * 1.0f);
                        float currentLayerMinAlpha =
                                minAlpha + alphaDelta * viewLayer / (maxLayerCount * 1.0f);
                        float realAlpha =
                                currentLayerMaxAlpha - (currentLayerMaxAlpha - currentLayerMinAlpha) * realFraction;

                        view.setScaleX(realScale);
                        view.setScaleY(realScale);
                        view.setAlpha(realAlpha);
                    }

                    @Override
                    public void handleFocusingView(FocusLayoutManager focusLayoutManager, Component view,
                                                   int position, float fraction, float offset) {
                        float realFraction = fraction;

                        float realScale =
                                0.85f + (1f - 0.85f) * realFraction;

                        float realAlpha = 1;

                        view.setScaleX(realScale);
                        view.setScaleY(realScale);
                        view.setAlpha(realAlpha);
                        view.setRotation(0);
                    }

                    @Override
                    public void handleNormalView(FocusLayoutManager focusLayoutManager, Component view,
                                                 int position, float fraction, float offset) {
                        view.setScaleX(0.85f);
                        view.setScaleY(0.85f);
                        view.setAlpha(1);
                        view.setRotation(0);
                    }
                });
                break;

            default:
                break;
        }
    }

    public class Adapter extends RecyclerContainer.Adapter {
        private final List<Bean> datas;
        private Context mContext;
        private int index = 0;

        public Adapter(Context context, List<Bean> datas) {
            this.mContext = context;
            this.datas = datas;
        }

        @Override
        public Adapter.ViewHolder createViewHolder(ContainerGroup parent, int viewType) {
            Component view = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_item_card, parent, false);

            if (focusLayoutManager.getFocusOrientation() == FocusLayoutManager.FOCUS_LEFT || focusLayoutManager.getFocusOrientation() == FocusLayoutManager.FOCUS_RIGHT) {
                ComponentContainer.LayoutConfig p = (RecyclerContainer.LayoutConfig) view.getLayoutConfig();
                p.setMarginTop((int)dp2px(view.getContext(),25));
                p.setMarginBottom((int)dp2px(view.getContext(),25));
                p.setMarginLeft((int)dp2px(view.getContext(),0));
                p.setMarginRight((int)dp2px(view.getContext(),0));
                p.width = (int) dp2px(view.getContext(), 100);
                p.height = (int) dp2px(view.getContext(), 150);
            } else {
                ComponentContainer.LayoutConfig p = (RecyclerContainer.LayoutConfig) view.getLayoutConfig();
                p.setMarginTop((int)dp2px(view.getContext(),0));
                p.setMarginBottom((int)dp2px(view.getContext(),0));
                p.setMarginLeft((int)dp2px(view.getContext(),25));
                p.setMarginRight((int)dp2px(view.getContext(),25));
                p.width = (int) dp2px(view.getContext(), 150);
                p.height = (int) dp2px(view.getContext(), 100);
            }
            view.setTag(++index);
            LogUtil.debug("ccy", "onCreateViewHolder = " + index);
            return new ViewHolder(view);
        }

        @Override
        public void bindViewHolder(RecyclerContainer.ViewHolder holder, int position) {
            int realPosition = cbInfinite.isChecked() ? position % datas.size() : position;
            Bean bean = datas.get(realPosition);

            ViewHolder viewHolder = (ViewHolder) holder;
            String path = getPathById(getContext(), bean.background);
            RawFileEntry assetManager = getContext().getResourceManager().getRawFileEntry(path);
            ImageSource.SourceOptions options = new ImageSource.SourceOptions();
            options.formatHint = IMAGE_FORMAT;
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();

            Resource asset = null;
            try {
                asset = assetManager.openRawFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            ImageSource source = ImageSource.create(asset, options);
            PixelMap pixelMap = source.createPixelmap(decodingOptions);

            viewHolder.iv.setPixelMap(pixelMap);
            viewHolder.tv.setText(bean.msg);
        }

        @Override
        public int getItemCount() {
            return cbInfinite.isChecked() ? Integer.MAX_VALUE : datas.size();
        }

        public class ViewHolder extends RecyclerContainer.ViewHolder {
            Text tv;
            Image iv;

            public ViewHolder(Component itemView) {
                super(itemView);
                tv = (Text) itemView.findComponentById(ResourceTable.Id_item_tv);
                iv = (Image) itemView.findComponentById(ResourceTable.Id_item_iv);

                itemView.setClickedListener(component -> {
                    mToast = null;
                    int pos = getLayoutPosition();

                    if (mToast == null) {
                            mToast = new ToastDialog(getContext());
                            mToast.setAlignment(LayoutAlignment.BOTTOM);
                            mToast.setDuration(2000);
                        }
                        mToast.setText("" + pos);
                        mToast.show();

                    if(pos == focusLayoutManager.getFocusdPosition()){
                        //Navigating to Detailed Image Ability
                        Intent intent = new Intent();
                        IntentParams in=new IntentParams();

                        in.setParam(RESOURCE_ID, datas.get(pos).background);
                        intent.addFlags(Intent.FLAG_ABILITY_NEW_MISSION);
                        intent.setParam(DETAILS, in);

                        present(new DetailAbilitySlice(), intent);
                    }
                    else{
                        focusLayoutManager.setFocusdPosition(pos, true);
                    }
                });
            }
        }

        String getPathById(Context context, int viewPathId) {
            String path = "";
            if (context == null) {
                LogUtil.error(TAG, "getPathById -> get null context");
                return path;
            }
            ResourceManager manager = context.getResourceManager();
            if (manager == null) {
                LogUtil.error(TAG, "getPathById -> get null ResourceManager");
                return path;
            }
            try {
                path = manager.getMediaPath(viewPathId);
            } catch (IOException e) {
                LogUtil.error(TAG, "getPathById -> IOException");
            } catch (NotExistException e) {
                LogUtil.error(TAG, "getPathById -> NotExistException");
            } catch (WrongTypeException e) {
                LogUtil.error(TAG, "getPathById -> WrongTypeException");
            }
            return path;
        }
    }

    public static class Bean {
        boolean useColor = true;
        int background;
        String msg;
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}
